package com.newland.starpos.partner.service;

import com.newland.starpos.partner.bean.UserInfo;
import com.newland.starpos.partner.bean.dto.UserDTO;
import com.newland.starpos.partner.bean.dto.UserLoginDTO;
import com.newland.starpos.partner.bean.dto.UserPwResetDTO;
import com.newland.starpos.partner.bean.dto.UserRegistDTO;
import com.newland.starpos.partner.bean.po.Regional;
import com.newland.starpos.partner.bean.po.User;
import com.newland.starpos.partner.bean.po.UserLogin;
import com.newland.starpos.partner.exception.CustomException;
import com.newland.starpos.partner.http.ResponseEnum;
import com.newland.starpos.partner.http.ResponseModel;
import com.newland.starpos.partner.listen.EventPublish;
import com.newland.starpos.partner.mapper.UserLoginMapper;
import com.newland.starpos.partner.mapper.UserMapper;
import com.newland.starpos.partner.service.function.RedisCache;
import com.newland.starpos.partner.service.remote.PortalService;
import com.newland.starpos.partner.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

/**
 * Created by liuNW on 2018/9/27.
 */
@Slf4j
@Service
public class UserService {

    @Autowired
    private EventPublish eventPublish;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserLoginMapper userLoginMapper;

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private AuthCodeService authCodeService;
    @Autowired
    private PortalService portalService;

    public static String tranPhoneNumber2UserName(String phoneNumber) {
        return "hhr" + phoneNumber + "01";
    }

    @Transactional(readOnly = true)
    public ResponseModel checkPhoneExist(String phoneNumber) {
        int number = userMapper.checkPhoneExist(phoneNumber);
        log.info("telephone[{}] exist find result [{}]", phoneNumber, number);
        return new ResponseModel(ResponseEnum.OK);
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseModel register(UserRegistDTO userRsgistDTO) throws CustomException {

        String phoneNumber = userRsgistDTO.getPhoneNumber();
        String authCode = userRsgistDTO.getAuthCode();

        if (!authCodeService.checkAuthCode(phoneNumber, authCode)) {
            return new ResponseModel(ResponseEnum.SMS_CODE_ERROR);
        }
        User newUser = new User();
        newUser.setTelephone(phoneNumber);
        newUser.setUserName(tranPhoneNumber2UserName(phoneNumber));

        Regional regional = userMapper.findRegionalByCode(userRsgistDTO.getRegionalCode());
        if (null == regional) {
            return new ResponseModel(ResponseEnum.REGIONAL_CODE_ERROR);
        }
        newUser.setRegionalId(regional.getRegionalId());
        newUser.setOrgId(regional.getOrgId());
        newUser.setOrgName(regional.getOrgName());

        // 有邀请码以邀请码来查找归属上级用户
        String inviteCode = userRsgistDTO.getInviteCode();
        if (StringUtils.isNotBlank(inviteCode)) {
            User parentUser = userMapper.findUserByInviteCode(inviteCode);
            // 邀请码错误
            if (null == parentUser) {
                return new ResponseModel(ResponseEnum.INVITE_CODE_ERROR);
            }
            newUser.setParentUserId(parentUser.getUserId());
            newUser.setOrgId(parentUser.getOrgId());
            newUser.setOrgName(parentUser.getOrgName());
            newUser.setLevel(parentUser.getLevel() + 1);//层级+1
        }
        // 再次验证手机号不存在
        if (userMapper.checkPhoneExist(phoneNumber) != 0) {
            return new ResponseModel(ResponseEnum.PHONENUMBER_EXIST);
        }

        String newInviteCode = uniqueInviteCode();
        newUser.setInviteCode(newInviteCode);
        userMapper.insert(newUser);
        // 如上面操作完成,此外维新增用户和其所有上层用户的对应关系
        if (StringUtils.isNotBlank(inviteCode)) {
            int rows = userMapper.insertUserRelation(newUser);
            log.info("新增用户关系数据,插入行数据：[{}]", rows);
        }
        // 调用portal生成用户和密码
        portalService.createUser(phoneNumber, regional.getOrgId());
        eventPublish.publishUserRegister(newUser);
        return new ResponseModel(ResponseEnum.OK);
    }

    private String uniqueInviteCode() {
        String key = "PT_USER_INVITECODE";
        String inviteCode = GenerateUtils.randomNumOrChar(8, true);
        boolean unique = redisCache.addSetIfAbsent(key, inviteCode);
        if (unique)
            return inviteCode;
        return uniqueInviteCode();
    }

    public UserInfo findUserInfo(String accessToken) {
        return userMapper.findUserInfo(accessToken);
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseModel login(UserLoginDTO userLoginDTO, HttpServletRequest request) throws CustomException {
        // 先本系统查找登录的用户
        String ip = IPUtils.getRealIP(request);
        String phoneNumber = userLoginDTO.getPhoneNumber();
        User loginUser = userMapper.findUserByPhone(phoneNumber);
        if (Objects.isNull(loginUser)) {
            return new ResponseModel(ResponseEnum.LOGIN_ERROR_USER_NOT_EXIST);
        }
        // 密码不做处理直接调用portal验证用户名和密码
        portalService.login(phoneNumber, userLoginDTO.getPassword(), request);

        log.info("[{}] 登录成功.", phoneNumber);
        // 1.把此用户的登录记录全部置为无效 2: invalid 1: valid
        List<String> tokens = userMapper.findToken(loginUser.getUserId());
        tokens.stream().forEach((String token) -> redisCache.delete("PT_UAT_" + token));
        userMapper.invalidToken(tokens);
        log.info("置为无效的登录信息记录条数为[{}]", tokens.size());
        // 2.记录登录信息并生成客户端访问token
        String token = UUID.randomUUID().toString();
        UserLogin login = new UserLogin();
        login.setUserId(loginUser.getUserId());
        login.setLoginTime(DateUtils.now());
        login.setEffective(1);
        login.setIpAddress(ip);
        login.setAccessToken(token);
        userLoginMapper.insert(login);

        UserDTO userDTO = BeanUtils.transfrom(UserDTO.class, loginUser);
        userDTO.setAccessToken(token);
        // 判断用户有没设置过支付密码
        int hasNotPayPw = StringUtils.isBlank(loginUser.getPaymentPassword()) ? 1 : 2;
        userDTO.setHasPayPw(hasNotPayPw);

        return new ResponseModel(ResponseEnum.OK, userDTO);
    }

    @Transactional(rollbackFor = Exception.class)
    public ResponseModel resetPassword(UserPwResetDTO userPwResetDTO, HttpServletRequest request) throws CustomException {
        // 验证码校验
        String authCode = userPwResetDTO.getAuthCode();
        String telephone = userPwResetDTO.getPhoneNumber();
        String newPassword = userPwResetDTO.getPassword();

        if (!authCodeService.checkAuthCode(telephone, authCode)) {
            return new ResponseModel(ResponseEnum.SMS_CODE_ERROR);
        }
        User user = userMapper.findUserByPhone(telephone);
        if (Objects.isNull(user)) {
            return new ResponseModel(ResponseEnum.USER_NOT_EXIST);
        }
        portalService.resetPassword(user, newPassword, request);
        log.info("密码重置成功.");
        user.setDefaultPw(2);
        userMapper.updateById(user);
        return new ResponseModel(ResponseEnum.OK);
    }

    public void UpdateUserPwType(User user) {
        user.setDefaultPw(2);
        userMapper.updateById(user);
    }
}
